use log::info;

use super::{conf, utils};
use std::{
    collections::HashMap,
    env,
    process::Command,
    thread::{self},
    time::{self},
};

pub struct Monitor<'a> {
    conf_v: &'a HashMap<String, conf::ConfItem>,
    ser_m: HashMap<String, i32>,
}
impl<'a> Monitor<'a> {
    pub fn new(c: &'a HashMap<String, conf::ConfItem>) -> Self {
        if env::consts::OS != "linux" {
            panic!("服务监控仅支持linux系统");
        }
        Monitor {
            conf_v: c,
            ser_m: HashMap::new(),
        }
    }
    /**
     * params: ps aux | grep sname | grep -v grep
     */
    pub fn check_exist(&self, ser_name: &str, ser_type: &str) -> bool {
        info!("begin check server type:{},name:{}", ser_type, ser_name);
        if ser_type == "local" {
            let cmd = format!("ps aux | grep {} | grep -v grep", ser_name);
            let out = Command::new("sh")
                .args(["-c", cmd.as_str()])
                .output()
                .expect("exec failed");
            info!(
                "check excute result {}, {:?}",
                out.status,
                String::from_utf8(out.stdout).unwrap()
            );
            return out.status.success();
        } else if ser_type == "docker" {
            let out = Command::new("docker")
                .args(["inspect", "--format", "'{{.State.Running}}'", ser_name])
                .output()
                .expect("exec failed");
            let res_str = String::from_utf8(out.stdout).unwrap();
            info!("check excute result {}, {:?}", out.status, res_str);
            if let Some(_) = res_str.find("true") {
                return true;
            }
        }
        false
    }
    pub fn start_server(&self, start_cmd: &str) -> bool {
        info!("beigin start server {}", start_cmd);

        let out = Command::new("sh")
            .args(["-c", start_cmd])
            .output()
            .expect("exec failed");
        info!(
            "excute result {}, {:?}",
            out.status,
            String::from_utf8(out.stdout).unwrap()
        );
        if out.status.success() {
            info!("service start success, cmd:{}", start_cmd);
            return true;
        }
        info!("service start failed, cmd:{}", start_cmd);
        false
    }
    pub fn run(&mut self) {
        loop {
            self.run_one();
            // 循环一次，暂停10s
            thread::sleep(time::Duration::from_secs(10));
        }
    }
    pub fn run_one(&mut self) {
        // 更新时间
        for c in self.conf_v {
            let sname = c.0;
            let sconf = c.1;
            info!("--- --- --- begin process {} --- --- ---", sname);
            if self.check_exist(sname, c.1.get_start_type()) {
                let v = self.ser_m.get_mut(sname);
                match v {
                    Some(v) => *v = utils::ts_sec(),
                    None => {
                        self.ser_m.insert(sname.clone(), utils::ts_sec());
                    }
                }
            } else {
                // 是否需要启动到期的服务
                let v = self.ser_m.get(sname);
                match v {
                    Some(last_ts) => {
                        info!("service not exist, offline {}", utils::ts_sec() - *last_ts);
                        if utils::ts_sec() - *last_ts > sconf.get_offline_interval() {
                            self.start_server(sconf.get_start_cmd());
                            *self.ser_m.get_mut(sname).unwrap() = utils::ts_sec();
                        }
                    }
                    None => {
                        self.start_server(sconf.get_start_cmd());
                        self.ser_m.insert(sname.clone(), utils::ts_sec());
                    }
                }
            }
            info!("--- --- --- end process {} --- --- ---", sname);
        }
    }
}
